<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
<script>
	// 定义一个shape()构造器
	function Shape() {
		this.name = 'Shape';
	}

	// 这种实现意味着我们用new Shape()创建的每个实体都会拥有一个全新的name属性，并在内存中拥有自己独立的储存空间。而事实上，我们也可以选择将name属性添加到原型上面去，这样一来所有的实体就可以共享这个属性了
	function Shape() {
		Shape.prototype.name = 'Shape';
	}

	// 这样一来，当我们再用new Shape()新建对象时，name属性就不再是新对象的私有属性了，而是被添加进了该对象的原型中。虽然这样做通常会更有效率，但这也只是针对对象实体中的不可变属性而言的，对象的共有方法尤其适合这种共享形式
	// 现在，让我们来改善一下之前的示例，将其所有的方法和那些符合条件的属性添加到原型对象中去，就Shape()和TwoDShape()而言，几乎所有东西都是可以共享的
	function Shape() {
		Shape.prototype.name = 'Shape';
		Shape.prototype.toString = function() {
			return this.name;
		}
	}

	function TwoDShape() {};

	TwoDShape.prototype = new Shape();
	TwoDShape.prototype.constructor = TwoDShape;
	TwoDShape.prototype.name = '2D shape';

	// 我们通常会在对原型对象进行扩展之前，先完成相关的继承关系构建，否则TwoDShape.prototype中的后续新内容有可能会抹掉我们之前所继承的东西。

	// 而Triangle构造器的情况稍许有些不同，因为由new Triangle()所创建的各个对象所表示的三角尺在尺寸上各不相同。因此，该对象的side和height这两个属性必须保持自身拥有，而其他的属性则可以设置共享。例如，方法getArea()的计算方式并不会随着每个Triangle实例而改变。另外，需要再情调一次，我们必须在扩展原型对象之前完成继承关系的构建

	function Triangle(side, height) {
		this.side = side;
		this.height = height;
	}

	Triangle.prototype = new TwoDShape();
	Triangle.prototype.constructor = Triangle;

	Triangle.prototype.name = 'Triangle';
	Triangle.prototype.getArea = function() {
		return this.side * this.height / 2;
	}

	// 修改完成后，之前所有的测试代码都可以用同样的方式应用于当前版本：
	var my = new Triangle(5, 10);
	console.log(my.getArea());
	console.log(my.toString());

	// 实际上调用my.toString()的区别仅仅存在于幕后的某些少量操作。主要区别也就是方法的查找操作将更多的发生在Shape.prototype中，而不再需要像前面实例中那样，到由new Shape()所创建的实体对象中查找了

	// 另外，我们可以通过hasOwnProperty()方法来明确对象自身属性与其原型链属性的区别
	console.log(my.hasOwnProperty('side'));
	console.log(my.hasOwnProperty('name'));

	// 而调用isPrototypeOf方法和instanceof操作符的工作方式与之前的并无区别，例如：
	console.log(TwoDShape.prototype.isPrototypeOf(my));
	console.log(my instanceof Shape);
</script>
</body>
</html>